package main.test.SparkAPI.Baics.classApi.HTTPserver

//import main.test.SparkAPI.Baics.classApi.{CAS, Currency, EUR, GBP, USD}
import main.test.SparkAPI.Baics.classApi._
// MyException class
class MyException(msg:String) extends Exception(msg)


object testHttpserver {

  def PatternMatching(): Unit ={
    /**
     * Write code use patt Match as altern TO AN
     * IF ELSE cosnstruct
     * PattMATCH over a closed set of values
     * after find how to express interface in scala using trait
     * see how to use pat mat.
     * Use PatMat as way to an if else, useful
     * when having many diff condi branches.
     * Scala patmAT looks simliar to switch/case stat of other langu
     * such as java js and c++.
     * It often more powful and versatile than in others,
     * due to its expressvie syntax and dedicated support for ealed elements and
     * classes.
     * In this less, learn how tpatmat compares to an if els
     * construct and its base use.
     * Discover how to define ptMat over a sealed set of values and how the compiler can
     * warn you if you foget to consider any of them.
     * PATMat ALSO DEDICATED supp for clss, but see how
     * this work later in book when learn about case clss.
     * use patMat to map country name to tiem zones
     */

    // if -- else vs pat mat
    /**
     * write func to convert number to its day of week , 1 for sunday.
     */
    def dayOfWeekUsingIFELSE(n:Int):String = {
      if (n==1) "Sunday"
      else if(n==2) "Monday"
      else if(n==3) "Tuesday"
      else if(n==4) "Wednesday"
      else if(n==5) "Thursday"
      else if(n==6) "Friday"
      else if(n==7) "Saturday"
      else "Unknown"
    }

    def dayOfWeekUsingPatMat(n: Int): String = n match {
      case 1 => "Sunday"
      case 2 => "Monday"
      case 3 => "Tuesday"
      case 4 => "Wednesday"
      case 5 => "Thursday"
      case 6 => "Friday"
      case 7 => "Saturday"
      case _ => "Unknown"
    }


    def objInfo(param:Any) = param match {
      case n:Int if n>0 => s"$n is a positive integer"
      case d:Double => s"$d is a double"
      case "ping" => "pong"
      case _:String => "you gave me a string"
      case obj => obj.toString
    }

    println(objInfo(true))
    println(objInfo("ping"))



    //SEALED patMat
    /**
     * the use sealed can let you define a closed set of poss
     * impl for trait
     * useful when combined with pattern mat.
     * Supp have following val to repr serv curiens
     * USD GBP EUR
     * NEED a fun exchangeRateUSD return USD exchange rate for given curr
     */
    def exchangeRateUSD(currency:Currency):Double =
      currency match {
        case USD => 1
        case GBP => 1.2
        case EUR => 0.848
        case CAS => 1.22
      }

    def discountOnPrice(price:Double):Double =
      price match {
        case x:Double if x<50 => x
        case y:Double if y>=50 && y<100 => 0.9*y
        case z:Double if z>=100 => 0.85*z
      }


  }

  def AnonyFuncs(): Unit = {
    import MyThirdCalculator._
    println(sum(3,5))
    val sumAny =  (a:Int, b:Int) => a+b
    val helloDef = { n:String => s"Hello, $n!"}
    println(sumAny(2,9))
    println(negate(9))
    println(helloDef("xiaoMing"))

    println(repeatStrNum("hellos",4))
    println(myLongFunc("very"))
    println(inverseConcat("hello","moring"))


  }

  def PartialFuncs(): Unit = {
    /**
     * Impl partial func to abs commonalities between funcs
     * create new funcs by composing partial funcs
     * Use try-catch expr to handle excepts
     *
     * Partial functions are functions that
     * are defined only for some input.
     * they useful to abstrac commility betwen func
     * you compose them to create more complex fucs
     * use partial fuc to catch and handle excepts
     * use partial fuc to define routes
     */
    /**
     * need to compute opers on integers
     * want to calcu sqrt of int.
     * This op is defn for nogneg nubs
     * negative int needed to return to neg int or zero.
     * use patMAt AND DEFINE TOW funcs
     */
    //sqrt of int
    def sqrtOrZero(n:Int):Double = n match {
      case x if x>=9 => Math.sqrt(n)
      case _ => 0

    }
    def sqrtOrValue(n:Int):Double = n match {
      case x if x>=0 => Math.sqrt(x)
      case x => x
    }

    /**
     * sqrtxxx are very similar
     * code duplication make it diff to maintain and keep consistent.
     * Use partial func to avoid repeating yourself.
     */

    //Impl a partial func
    /**
     * it is a func you define for some instances of a type.
     * you have encountered examp of partial fuc when
     * discs patMat: each case clause a part func
     * defin a part func to comput sqrt of nonne int
     */
    //    You can read
    //    PartialFunction[Int, Double]
    //    as “partial function from
    //    int to double.”
    /**
     * In Scala, the type PartialFunction[A, B] identifies a
     * partial function of a parameter of type A
     * \that returns an instance of type B.
     */
    val sqrt:PartialFunction[Int,Double] =
      { case x if x>=0 => Math.sqrt(x)}
//    println(sqrt(-9))
    val toPrettyString:PartialFunction[Any, String] = {
      case x:Int if x>0 => s"positive number: $x"
      case s:String => s
    }

    /**
     * Define a partial function called transform that reverses strings
     * sarting with an "a" and converts to uppercase all those beginning with
     * "s" Use startWith, reverse, toUpperCase func of class String
     *
     */
    val transform:PartialFunction[String,String] = {
      case  s:String if s.startsWith("a") => s.reverse
      case s:String if s.startsWith("s") => s.toUpperCase
    }
    println(transform("abcde"))
    println(transform("sapKad"))
    //func composition
    /**
     * val f:String => Int =>_.size
     * val g:Int => Boolean = _>2
     * you can create func by call f and g
     * val gof:String=>Boolean = f.andThen(g)
     */
    val f:String => Int = _.size
    val g:Int => Boolean = _>2
    val gof:String =>Boolean = f.andThen(g)

    /**
     * here compo is not this meaning.
     * you want comb 2 par func as fallbacks if prev part func couldnt match
     * given input
     * you can comp part as falbak using orElse
     *
     */
    //how you can refactor your square root functions to remove the code duplication
    val zeroRet:PartialFunction[Int,Double] = { case _ => 0}
    val values:PartialFunction[Int,Double] ={ case x => x}
    def sqrtWithZero(n:Int):Double = sqrt.orElse(zeroRet)(n)
    def sqrtWithValue(n:Int):Double = sqrt.orElse(values)(n)











  }


  def testExcept() ={
    //use case:EXCEPT handing
    /**
     * try-catch expr is another par func
     * excp hand come from java world, any class that extends java.lang.Exception
     * is an exception. it interupts your code;s exe flow:need to intercept it or it will terminate your pro
     * java.lang pack affors some excpets
     * a few are RuntimeException, NullPointerException, IllegalStateException,
     * IllegalArgumentException, NumberFormatException
     * extending java.lang.Exception class to udf a exception
     *
     * //TODO:  using keyword throw TO interrupt your pro.
     *            throw new MyException("BOOM!")
     *  after raising an expt, need to catch it before terminates your pro
     *  use try-cat expr
     *
     *
     *
     */
    def n():Int =
      try {
        throw new Exception("Boom!!")
        42
      } catch {
        case ex:Exception =>
          println(s"Ignoring exception $ex. Returning zero instead")
          0
      }

    println(n())

    /**
     * catch keyw follow part func that identi which expt it should handle:
     * if expt dosent match, it will not intercept it.
     *
     * Avoid exceptions
     * scala reuse jva code that heavily uses except.
     * some of its stand lib and func also throw them.
     * knowing how to deal it is key
     * you shold avoid using excpt .
     * expt are equal to ticking bomb. they will
     * explode and kill pro unless some is ready to defuse them.
     * expt are unpred.idenf which excpet a fun could throw is
     * particly changlge. its sig doesnt give you info. you can doc and
     * annot which expt it thrw, but this is not cotrled or enfrecd at compil time
     * so you no guaree thy still accrte or coret.
     * your opt is to look at its impl while hunting for expt, not easy as they will
     * hide any of its iner func calls
     * expt are darastic soltion.
     */
    val b: Boolean =
      try {
        "hello".toBoolean
      } catch {
        case ex:Exception =>
          println(s"Ignoring exception $ex. Returning false instead")
          false
      }
    println(b)

    def string2Int(s:String):Int = {
      try {
        s.toInt
      } catch {
        case ex:Exception =>
          println(s"ignore exception $ex. Return its length instead")
          s.length
      }
    }
    println(string2Int("23.2"))

    def defaultHandling(S:String) = {
      var x = 7
      try {
        S.toInt
        x = 9
      } catch {
        case ex:Exception => {
          println(s"ingore exception $ex, going on...")
          x = 12+4+1
        }

      }
//      x = 12
      println(s"x = $x")
    }
    defaultHandling("3to9")
  }
  def HttpApiWithHTTP4S() ={
    /**
     * Run an Http server using sbt
     * Impl an api to handle get requests
     * After partial funcs, use them as part of your impl of
     * an http server.
     * Build an Http server without external lib would require lots
     * of extr time and code.
     * SCALA ecosystem offers a few external lib to handle http comm
     * Learn about http4s, lib to mange Http REQ and resp.
     * Discover how to impl an http server replies to GET/ping
     * req with a response with status code 200-Ok and
     * text "pong"
     * Final, see how to run suing sbt.
     * Use https to create Http Server and define its API
     */

    /**
     * Overview of http4s
     * Typelevel is noprf  org to promote
     * purely functional opensource scala proj
     * togth with inclusive and welcoming env.
     * A Giter8 template for http4s
     * generate a simple HTTP server
      * that replies to an /hello/world endpoint
     *  See https://hub.fastgit.org/http4s/http4s.g8
     *  for details.
     *
     *  need to link your routes to their business logic through instances of
     *  org.http4s.HttpRoutes
     *
     *  Each HttpRoutes uses partial functions to match an incoming
HTTP request, and it produces an HTTP response together with a side effect (e.g., an IO
read/write, a connection to a third party).

     *
     *
     */


  }

  def main(args: Array[String]): Unit = {
//    PatternMatching()
//    AnonyFuncs()
//    PartialFuncs()
    testExcept


  }
}
